import VueApollo from 'vue-apollo';
import { GlSkeletonLoader, GlSprintf } from '@gitlab/ui';
import Vue from 'vue';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import VulnerabilityFileContents from 'ee/vulnerabilities/components/vulnerability_file_contents.vue';
import vulnerabilityBlobInfoQuery from 'ee/security_dashboard/graphql/queries/vulnerability_blob_info.query.graphql';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import CodeBlockHighlighted from '~/vue_shared/components/code_block_highlighted.vue';

Vue.use(VueApollo);

const sha = 'cdeda7ae724a332e008d17245209d5edd9ba6499';
const file = 'file.js';

const location = {
  blobPath: `/project/-/blob/${sha}/${file}`,
  startLine: 2,
  endLine: 4,
  file: 'file.js',
};

const blobData = {
  id: 1,
  rawTextBlob: 'line 1\nline 2\nline 3\nline 4\nline 5',
  language: 'js',
};

describe('Vulnerability File Contents component', () => {
  let wrapper;

  const getMutationResponse = ({ blob = blobData } = {}) =>
    jest.fn().mockResolvedValue({
      data: {
        project: { id: 1, repository: { blobs: { nodes: [blob] } } },
      },
    });

  const createWrapper = ({ mutationResponse = getMutationResponse() } = {}) => {
    wrapper = shallowMountExtended(VulnerabilityFileContents, {
      apolloProvider: createMockApollo([[vulnerabilityBlobInfoQuery, mutationResponse]]),
      provide: { projectFullPath: 'path/to/project' },
      propsData: { location },
      stubs: { GlSprintf },
    });
  };

  describe('loading and error states', () => {
    it('shows skeleton loader when loading', () => {
      createWrapper();

      expect(wrapper.findComponent(GlSkeletonLoader).exists()).toBe(true);
    });

    it('shows an error if query failed', async () => {
      createWrapper({ mutationResponse: jest.fn().mockRejectedValue() });
      await waitForPromises();

      expect(wrapper.findByTestId('loading-error').text()).toBe(
        'Something went wrong while trying to get the source file.',
      );
    });

    it('shows a warning if the file was not found', async () => {
      createWrapper({ mutationResponse: getMutationResponse({ blob: null }) });
      await waitForPromises();

      expect(wrapper.findByTestId('file-not-found-warning').text()).toBe(
        `${file} was not found in commit ${sha}`,
      );
    });
  });

  describe('file contents loaded', () => {
    beforeEach(() => {
      createWrapper();
      return waitForPromises();
    });

    it('shows the correct line numbers', () => {
      expect(wrapper.findByTestId('line-numbers').text()).toMatchInterpolatedText('2 3 4');
    });

    it('shows the source code', () => {
      expect(wrapper.findComponent(CodeBlockHighlighted).props()).toMatchObject({
        code: 'line 2\nline 3\nline 4',
        language: blobData.language,
      });
    });
  });
});
